/*
 *  SuperAggroAI.cpp
 *  RiskAI
 *
 *  Created by Chris on 11/15/09.
 *  Copyright 2009 __MyCompanyName__. All rights reserved.
 *
 */

#include "SuperAggroAI.h"
#include "Board.h"
#include "Territory.h"

#include <iostream>

using namespace std;

//**********************************************************************************
//				CONSTRUCTION/DESTRUCTION
//**********************************************************************************

CSuperAggroAI::CSuperAggroAI(int iIndex, CBoard* pxBoard)
	: CPlayer(iIndex, pxBoard)
	, m_bBudgetCalculated(false)
{
}



//**********************************************************************************
//				HELPER FUNCTIONS
//**********************************************************************************

void
CSuperAggroAI::GetOffensiveTerritories()
{
	/*
	 *	Compiles a list of territories that border territories owned
	 *	by enemy players.
	 */
	
	m_viOffense.clear();
	
	for(unsigned int i=0; i<m_viTerritories.size(); i++)
	{
		int iIndex = m_viTerritories[i];
		vector<int> viBorders = m_pxBoard->GetTerritory(iIndex)->GetBorderIndices();
		for(unsigned int j=0; j<viBorders.size(); j++)
		{
			int iOwner = m_pxBoard->GetTerritory(viBorders[j])->GetOwner();
			if(iOwner != m_iIndex)
			{
				m_viOffense.push_back(iIndex);
				break;
			}
		}
	}
}

//==================================================================================

void
CSuperAggroAI::CalculateBudget(int iNumTroops)
{
	/*
	 *  Clear old states
	 */
	m_miiBudget.clear();
	GetOffensiveTerritories();

	/*
	 *  Figure out how many troops I have to work with, keeping in mind
	 *	that one troop in each of my territories is useless for attacking
	 */
	int iTroopTotal = iNumTroops;
	int iEnemyTotal = 0;
	for(unsigned int i=0; i<m_viOffense.size(); i++)
	{
		iTroopTotal += m_pxBoard->GetTerritory(m_viOffense[i])->GetNumArmies() - 1;
		iEnemyTotal += m_pxBoard->EnemiesSurroundingTerritory(m_viOffense[i]);
	}
	
	
	/*
	 *  Figure out how many troops I want in each territory.
	 */
	double dRatio = double(iTroopTotal) / double(iEnemyTotal);
	for(unsigned int i=0; i<m_viOffense.size(); i++)
	{
		int iTroops  = m_pxBoard->GetTerritory(m_viOffense[i])->GetNumArmies();
		int iEnemies = m_pxBoard->EnemiesSurroundingTerritory(m_viOffense[i]);
		
		int iGoal = double(iEnemies * dRatio + 1.5);
		
		m_miiBudget[m_viOffense[i]] = iGoal - iTroops;
	}
}





//**********************************************************************************
//				VIRTUAL FUNCTIONS
//**********************************************************************************

int
CSuperAggroAI::PickTerritory(vector<int> viAvailables)
{
	/*
	 *  Find a territory that borders an opponent. If that doesn't work out,
	 *  just pick something at random >:(
	 */
	
	
	for(unsigned int i=0; i<viAvailables.size(); i++)
	{
		int iIndex = viAvailables[i];
		vector<int> viBorders = m_pxBoard->GetTerritory(iIndex)->GetBorderIndices();
		for(unsigned int j=0; j<viBorders.size(); j++)
		{
			int iOwner = m_pxBoard->GetTerritory(viBorders[j])->GetOwner();
			if(iOwner != -1 && iOwner != m_iIndex)
				return iIndex;
		}
	}
	
	int iIndex = rand() % viAvailables.size();
	return viAvailables[iIndex];
}

//==================================================================================

int
CSuperAggroAI::AssignTroops(int iNumTroops)
{
	/*
	 *  Distribute troops to offensive territories weighted by how many
	 *  enemy armies are adjacent to those territories (more armies go to
	 *  territories where they can do more damage).
	 */
		
	if(!m_bBudgetCalculated)
	{
		CalculateBudget(iNumTroops);
	}
	
	int iNeedsMost;
	int iMostNeeded = -1;
	for(unsigned int i=0; i<m_viOffense.size(); i++)
	{
		if(m_miiBudget[m_viOffense[i]] > iMostNeeded)
		{
			iMostNeeded = m_miiBudget[m_viOffense[i]];
			iNeedsMost = m_viOffense[i];
		}
	}
	
	m_miiBudget[iNeedsMost]--;
	
	if(iNumTroops == 1) m_bBudgetCalculated = false;
	
	return iNeedsMost;
}

//==================================================================================

int
CSuperAggroAI::MoveTroops(int iSourceIndex, int iDestinationIndex)
{
	int iSourceTroops = m_pxBoard->GetTerritory(iSourceIndex)->GetNumArmies();
	int iSourceEnemies = m_pxBoard->EnemiesSurroundingTerritory(iSourceIndex);
	
	int iDestTroops = m_pxBoard->GetTerritory(iDestinationIndex)->GetNumArmies();
	int iDestEnemies = m_pxBoard->EnemiesSurroundingTerritory(iDestinationIndex);
	
	if(iSourceEnemies - iSourceTroops >= iDestEnemies - iDestTroops)
		return 0;
	else
	{
		return min(max(iDestEnemies - iDestTroops, 0), max(iSourceTroops - 1, 0));
	}
}

//==================================================================================

RiskAction
CSuperAggroAI::DecideOnAction(vector<int> viViableAttackers)
{
	/*
	 *	Uses a territory (it doesn't matter which one, it uses them all
	 *	eventually) to attack the neighbor with the most armies. If there
	 *  is a tie for most armies, it is broken at random.
	 */
	
	int iSource = viViableAttackers[0];
	int iTargetEnemies = 0;
	vector<int> viPossibles;
	
	vector<int> viBorders = m_pxBoard->GetTerritory(iSource)->GetBorderIndices();
	for(unsigned int i=0; i<viBorders.size(); i++)
	{
		int iIndex = viBorders[i];
		int iTroops = m_pxBoard->GetTerritory(iIndex)->GetNumArmies();
		int iOwner = m_pxBoard->GetTerritory(iIndex)->GetOwner();
		if(iOwner != m_iIndex && iTroops > iTargetEnemies)
		{
			iTargetEnemies = iTroops;
			viPossibles.clear();
			viPossibles.push_back(iIndex);
		}
		
		if(iOwner != m_iIndex && iTroops == iTargetEnemies)
		{
			viPossibles.push_back(iIndex);
		}
	}
	int iTarget = viPossibles[rand() % viPossibles.size()];
	
	int iDice = min(m_pxBoard->GetTerritory(iSource)->GetNumArmies() - 1, 3);
	
	return RiskAction(iSource, iTarget, iDice);
}

//==================================================================================

int
CSuperAggroAI::PickDefendingDie(int* aiAttackDice, int iTarget)
{
	return min(2, m_pxBoard->GetTerritory(iTarget)->GetNumArmies());
}

//==================================================================================

CFortification
CSuperAggroAI::FortifyTroops(vector<int> viFortifiers)
{
	/*
	 *	Find territory in fortification range that needs troops the most.
	 *	Assumes that at this point, any territory that can make a fortification
	 *  is not next to any enemy territories (otherwise he'd have attacked it).
	 */
	
	int iNeedsMost = -1;
	int iMostNeeded = 0;
	
	for(unsigned int i=0; i<viFortifiers.size(); i++)
	{
		vector<int> viBorders = m_pxBoard->GetTerritory(viFortifiers[i])->GetBorderIndices();
		for(unsigned int j=0; j<viBorders.size(); j++)
		{
			int iIndex = viBorders[j];
			int iEnemies = m_pxBoard->EnemiesSurroundingTerritory(iIndex);
			if(iEnemies > iMostNeeded)
			{
				iNeedsMost = iIndex;
				iMostNeeded = iEnemies;
			}
		}
	}
	
	
	/*
	 *	If there's one one in range who needs help, do nothing.
	 */
	
	if(iNeedsMost == -1) return NO_FORTIFICATION;
	
	
	/*
	 *	Find the territory best equipped to help. Move all available troops
	 *  from there to the needy one.
	 */
	int iHasMost;
	int iMostHad = 0;
	
	vector<int> viBorders = m_pxBoard->GetTerritory(iNeedsMost)->GetBorderIndices();
	for(unsigned int i=0; i<viBorders.size(); i++)
	{
		int iIndex = viBorders[i];
		if(m_pxBoard->GetTerritory(iIndex)->GetOwner() != m_iIndex)
			continue;
		
		int iTroops = m_pxBoard->GetTerritory(iIndex)->GetNumArmies();
		if(iTroops > iMostHad)
		{
			iHasMost = iIndex;
			iMostHad = iTroops;
		}
	}
	
	return CFortification(iHasMost, iNeedsMost, iMostHad - 1);
}